//+------------------------------------------------------------------+
//| 邮件发送辅助函数                                                    |
//+------------------------------------------------------------------+
void SendFormattedEmail(string subject, string message_type, datetime bar_time, double bar_close)
{
    // 获取时区偏移量（分钟）并格式化为字符串
    int offset_minutes = TimeGMTOffset() / 60;
    int offset_hours = offset_minutes / 60;
    string timezone_str = "GMT" + (offset_hours >= 0 ? "+" : "") + IntegerToString(offset_hours);

    // 格式化邮件正文
    string full_body = message_type;
    // 使用 TIME_DATE | TIME_SECONDS 格式化时间，使其包含年月日时分秒
    full_body += "时间: " + TimeToString(bar_time, TIME_DATE|TIME_SECONDS) + " (" + timezone_str + ")\n";
    full_body += "货币对: " + Symbol() + "\n";
    full_body += "图表周期: " + EnumToString(_Period) + "\n";
    full_body += "收盘价: " + DoubleToString(bar_close, _Digits); 
    
    // 发送邮件并打印日志
    // 注意: 请确保在MT5客户端的 \"工具 -> 选项 -> 电邮\" 中已正确配置邮箱设置
    SendMail(subject, full_body);
    Print("邮件已发送: ", subject, " - ", full_body);
}


//+------------------------------------------------------------------+
   //|                                                           m1.mql5 |
   //|                        Copyright 2024, MetaQuotes Software Corp. |
   //|                                             https://www.mql5.com |
   //+------------------------------------------------------------------+
   #property copyright "Copyright 2024, MetaQuotes Software Corp."
   #property link      "https://www.mql5.com"
   #property version   "1.00"
   //主图indicator_chart_window  副图 indicator_separate_window
   #property indicator_chart_window
   #property indicator_buffers 2
#property indicator_plots   2

// 枚举类型定义
enum ENUM_INPUT_YES_NO
{
   INPUT_YES = 1, // Yes
   INPUT_NO = 0   // No
};

//--- input parameters

// 已移除 Peak-Valley 参数

// 神龙通道参数
input int DragonQual = 8;  // 神龙通道质量参数
input int DragonLen = 18;   // 神龙通道长度参数
input ENUM_INPUT_YES_NO DragonAlert = INPUT_YES;     // 神龙弹窗警报
input ENUM_INPUT_YES_NO DragonMail = INPUT_YES;     // 神龙邮件通知
input double DragonOffsetPoints = 10.0; //(计算显示位置)神龙通道箭头偏移点数 (推荐: 外汇5-20, 黄金30-100, 指数10-50)
input ENUM_INPUT_YES_NO DragonUseATR = INPUT_YES; //(计算显示位置) 使用ATR动态偏移
input int DragonATRPeriod = 14; //(计算显示位置) ATR周期
input double DragonATRMultiplier = 0.3; //(计算显示位置神龙信号) ATR倍数 (0.1-1.0)


// 已删除MA填充区域参数

// 已删除K线颜色设置参数

// 已删除MA填充区域绘图设置

// 已移除红线和绿线

// 已移除 趋势线和Peak-Valley箭头

//--- plot 神龙通道上箭头
#property indicator_label1  "神龙通道上箭头"
#property indicator_type1   DRAW_ARROW
#property indicator_color1  clrMagenta
#property indicator_style1  STYLE_SOLID
#property indicator_width1  2

//--- plot 神龙通道下箭头
#property indicator_label2  "神龙通道下箭头"
#property indicator_type2   DRAW_ARROW
#property indicator_color2  clrDeepSkyBlue
#property indicator_style2  STYLE_SOLID
#property indicator_width2  2

   //--- indicator buffers
   // 已移除红线和绿线缓冲区
   double DragonUpBuffer[];       // 神龙通道上箭头缓冲区
   double DragonDownBuffer[];     // 神龙通道下箭头缓冲区

   
   //--- 神龙通道全局变量
   int dragon_bindex;  // 神龙通道上涨计数器
   int dragon_sindex;  // 神龙通道下跌计数器
   

   
   //--- ATR handle for dragon channel
   int atr_handle;

   //+------------------------------------------------------------------+
   //| Custom indicator initialization function                         |
   //+------------------------------------------------------------------+
   int OnInit()
   {
   // 生成唯一的指标短名称，避免多实例冲突
   string uniqueID = IntegerToString(GetTickCount() + MathRand());
   IndicatorSetString(INDICATOR_SHORTNAME, "综合指标B-v5 #" + uniqueID);
   
   //--- indicator buffers mapping
   SetIndexBuffer(0, DragonUpBuffer, INDICATOR_DATA);       // 神龙通道上箭头 (第1个plot)
   SetIndexBuffer(1, DragonDownBuffer, INDICATOR_DATA);     // 神龙通道下箭头 (第2个plot)

   // 已删除MA填充区域的所有设置代码
   
   // 已移除 Peak-Valley 箭头设置
   
   // 设置神龙通道箭头属性
   PlotIndexSetInteger(0, PLOT_ARROW, 233);  // 神龙通道上箭头 (第1个plot)
   PlotIndexSetInteger(1, PLOT_ARROW, 234);  // 神龙通道下箭头 (第2个plot)
   PlotIndexSetDouble(0, PLOT_EMPTY_VALUE, EMPTY_VALUE);
   PlotIndexSetDouble(1, PLOT_EMPTY_VALUE, EMPTY_VALUE);
   
   // 设置神龙通道箭头的绘制起始位置
   PlotIndexSetInteger(0, PLOT_DRAW_BEGIN, 20);
   PlotIndexSetInteger(1, PLOT_DRAW_BEGIN, 20);
   
   // 设置神龙通道缓冲区为正常模式（不使用时间序列）
   ArraySetAsSeries(DragonUpBuffer, false);
   ArraySetAsSeries(DragonDownBuffer, false);
   
   // 初始化神龙通道计数器
   dragon_bindex = 0;
   dragon_sindex = 0;

//--- set precision
   IndicatorSetInteger(INDICATOR_DIGITS, _Digits);

//--- sets first bar from what index will be drawn
   PlotIndexSetInteger(0, PLOT_DRAW_BEGIN, 20);   // 神龙上箭头
   PlotIndexSetInteger(1, PLOT_DRAW_BEGIN, 20);   // 神龙下箭头

      //--- 创建ATR句柄用于神龙通道动态偏移
      atr_handle = iATR(NULL, 0, DragonATRPeriod);
      
      if(atr_handle == INVALID_HANDLE)
      {
         Print("创建ATR句柄失败");
         return(INIT_FAILED);
      }
      
      // 已删除K线颜色设置功能

      return(INIT_SUCCEEDED);
   }

   //+------------------------------------------------------------------+
   //| Custom indicator iteration function                              |
   //+------------------------------------------------------------------+
   int OnCalculate(const int rates_total,
                  const int prev_calculated,
                  const datetime &time[],
                  const double &open[],
                  const double &high[],
                  const double &low[],
                  const double &close[],
                  const long &tick_volume[],
                  const long &volume[],
                  const int &spread[])
   {
      if(rates_total < 200) return(0);
      
      // 调整神龙通道缓冲区大小
      ArrayResize(DragonUpBuffer, rates_total);
      ArrayResize(DragonDownBuffer, rates_total);
      
      // --- 获取ATR数据用于动态偏移计算
      double atr_data[];
      ArrayResize(atr_data, rates_total);
      
      if(CopyBuffer(atr_handle, 0, 0, rates_total, atr_data) <= 0)
      {
         return(0);
      }
      
      int limit = prev_calculated == 0 ? 200 : prev_calculated - 1;
      
      // 神龙通道计算起始位置
      int dragon_start = 20;
      if(prev_calculated > 0) 
         dragon_start = prev_calculated - 1;
      
      
      // ========== 神龙通道计数器逻辑修正 ==========
      // 使用静态变量记录上次信号触发的位置，避免重复计算
      static int last_signal_bar = -1;
      static bool signal_triggered = false;
      static datetime last_dragon_up_time = 0;   // 神龙通道上箭头最后报警时间
      static datetime last_dragon_down_time = 0; // 神龙通道下箭头最后报警时间
      static int last_dragon_up_bar = -1;        // 神龙通道上箭头最后报警K线索引
      static int last_dragon_down_bar = -1;      // 神龙通道下箭头最后报警K线索引
      static bool dragon_first_run = true;       // 标记是否是首次运行
      static int dragon_init_call_count = 0;     // 记录初始化调用次数
      
      // 记录初始化调用次数
      if(prev_calculated == 0)
      {
         dragon_init_call_count++;
         Print("[神龙通道] 初始化调用次数: ", dragon_init_call_count);
      }
      
      // 只在新K线时重新计算计数器
      if(prev_calculated == 0 || rates_total > prev_calculated + 1)
      {
         dragon_sindex = 0; // 重置下跌计数器
         dragon_bindex = 0; // 重置上涨计数器
         signal_triggered = false;
         last_signal_bar = -1;
         
         // 首次初始化时重置报警记录
         if(prev_calculated == 0 && dragon_init_call_count == 1)
         {
            last_dragon_up_time = 0;
            last_dragon_down_time = 0;
            last_dragon_up_bar = -1;
            last_dragon_down_bar = -1;
         }
         
         // 从dragon_start开始重新计算累积计数
         for(int j = dragon_start; j < rates_total; j++)
         {
            if(j >= 4) // 确保有足够的历史数据进行比较
            {
               // 价格趋势判断：比较当前收盘价与4根K线前的收盘价
               bool price_up = close[j] > close[j-4];     // 当前价格高于4根K线前 -> 上涨趋势
               bool price_down = close[j] < close[j-4];   // 当前价格低于4根K线前 -> 下跌趋势
               
               // 累积计数逻辑
               if(price_up)
               {
                  dragon_bindex += 1;
               }
               if(price_down)
               {
                  dragon_sindex += 1;
               }
            }
         }
         
         // 输出当前累积计数状态（仅在调试时）
         Print("[神龙通道] 重新计算累积计数: dragon_bindex=", dragon_bindex, ", dragon_sindex=", dragon_sindex, ", DragonQual=", DragonQual);
      }
      
      for(int i = limit; i < rates_total; i++)
      {
         
         // ========== 神龙通道计算逻辑 ==========
         // 神龙通道是一个基于价格趋势反转的箭头信号指标
         // 核心思想：统计连续上涨/下跌次数，当达到阈值且满足特定条件时产生反转信号
         // 基于原始神龙通道指标逻辑实现
         if(i >= dragon_start)
         {
            
            // ========== 第二步：初始化缓冲区 ==========
            // 初始化神龙通道箭头缓冲区为空值
            DragonUpBuffer[i] = EMPTY_VALUE;      // 上涨箭头缓冲区
            DragonDownBuffer[i] = EMPTY_VALUE;    // 下跌箭头缓冲区
         
            // ========== 第三步：计算箭头显示位置的智能偏移量 ==========
            // 智能偏移量用于确定箭头在图表上的显示位置
            // 可以选择ATR动态偏移或固定点数偏移
            double smart_offset;
            if(DragonUseATR == INPUT_YES && i >= DragonATRPeriod)
            {
               // 使用ATR动态偏移：根据市场波动性自动调整箭头位置
               // ATR值 * 倍数，确保最小偏移为3个点
               // ATR越大，市场波动越大，箭头偏移也越大，避免与价格重叠
               smart_offset = MathMax(atr_data[i] * DragonATRMultiplier, _Point * 3);
            }
            else
            {
               // 使用固定点数偏移：固定的点数偏移量
               // 适用于波动性相对稳定的市场或用户偏好固定偏移的情况
               smart_offset = _Point * DragonOffsetPoints;
            }
            
            // ========== 第四步：下跌信号判断与触发 ==========
            // 下跌信号触发条件（五个条件必须同时满足）：
            // 1. dragon_bindex > DragonQual：连续上涨次数超过质量阈值（表明已有足够的上涨动能，准备回调）
            // 2. close[i] < open[i]：当前K线为阴线（价格开始回落的确认信号）
            // 3. high[i] >= iHigh(...)：当前最高价达到或超过DragonLen周期内的最高点（触及阻力位）
            // 4. i < rates_total - 1：确保K线已收盘（不是当前正在形成的K线）
            // 5. 防止重复信号：确保不在同一K线上重复触发信号
            // 注意：原始指标使用 rates_total-1-(i-1) = rates_total-i 来计算iHighest的shift参数
            // 这个计算方式是为了从当前位置向前回看DragonLen个周期 比如 20 个周期 
            // dragon_bindex 统计连续上涨的次数
            // DragonQual 连续上涨的次数超过质量阈值（表明已有足够的上涨动能，准备回调）
            if((dragon_bindex > DragonQual) && (close[i] < open[i]) && 
               (high[i] >= iHigh(NULL, 0, iHighest(NULL, 0, MODE_HIGH, DragonLen, rates_total-1-(i-1)))) &&
               // 已移除趋势线过滤条件
               (i < rates_total - 1))  // 确保K线已收盘
            {
               // 详细信号触发日志
               Print("[神龙通道] *** 下跌信号触发 *** K线[", i, "] dragon_bindex=", dragon_bindex, ", DragonQual=", DragonQual);
               Print("[神龙通道] 触发条件: close[", i, "]=", close[i], " < open[", i, "]=", open[i], ", high[", i, "]=", high[i]);
               Print("[神龙通道] K线收盘确认: i=", i, " < rates_total-1=", rates_total-1, " (K线已收盘)");
               Print("[神龙通道] 信号位置: high[", i, "]=", high[i], ", 偏移=", smart_offset, ", 箭头位置=", high[i] + smart_offset);
               Print("[神龙通道] 设置下跌箭头: DragonDownBuffer[", i, "] = ", high[i] + smart_offset);
               
               // 记录信号触发状态，防止重复信号
               signal_triggered = true;
               last_signal_bar = i;
               
               // 在最高价上方显示下跌箭头（加上偏移量避免与价格重叠）
               DragonDownBuffer[i] = high[i] + smart_offset;
               
               // ========== 警报和通知逻辑 ==========
               // 确定警报基于的K线位置
               int whichBar = i;  // 默认基于前一根K线
               // if (DragonCurrentBar == INPUT_YES) whichBar = i;  // 可选择基于当前K线
               
               // 只对最新的几根K线触发警报，避免历史数据弹窗
               // 只有当信号出现在最近3根K线内时才触发警报
               // 第一次加载时（prev_calculated == 0）也允许最近的信号报警
               bool isRecentSignal = (i >= rates_total - 3);
               
               // 使用K线时间和索引双重防止重复报警
               datetime signal_time = time[i];
               // 检查冷却期：信号触发后至少3根K线内不再触发
               bool inCooldown = false;
               if(last_dragon_down_bar >= 0 && i - last_dragon_down_bar < 3)
               {
                  inCooldown = true;
               }
               
               // 调试信息
               Print("[神龙通道-下] 检查报警条件: i=", i, ", rates_total=", rates_total, ", isRecentSignal=", isRecentSignal, 
                     ", signal_time=", TimeToString(signal_time), ", last_dragon_down_time=", TimeToString(last_dragon_down_time),
                     ", last_dragon_down_bar=", last_dragon_down_bar, ", inCooldown=", inCooldown, 
                     ", prev_calculated=", prev_calculated, ", dragon_init_call_count=", dragon_init_call_count);
               
               // 首次运行时需要特殊处理，避免重复报警
               bool shouldAlert = false;
               if(prev_calculated == 0 && dragon_init_call_count <= 2)
               {
                  // 初始化阶段，只在第一次调用且是最新信号时报警
                  shouldAlert = isRecentSignal && !inCooldown && (i == rates_total - 2) && (dragon_init_call_count == 1);
               }
               else
               {
                  // 非首次运行，正常检查
                  shouldAlert = isRecentSignal && !inCooldown && last_dragon_down_time != signal_time;
               }
               
               if (shouldAlert)
               {
                  Print("[神龙通道-下] 满足报警条件，准备发送报警");
                  
                  // 弹窗警报
                  if (DragonAlert == INPUT_YES)
                  {
                     string alert_message = Symbol() + ", " + TimeframeToString(Period()) + ": Reverse:Arrow down " + TimeToString(signal_time);
                     Alert(alert_message);
                     Print("[神龙通道] 发送警报: ", alert_message);
                  }
                  
                  // 邮件通知
                  if (DragonMail == INPUT_YES && TerminalInfoInteger(TERMINAL_EMAIL_ENABLED))
                  {
                     SendFormattedEmail(" Reverse:Arrow down", "信号类型:  Reverse:Arrow down\n", time[i], close[i]);
                     Print("[神龙通道] 发送邮件: Reverse:Arrow down");
                  }
                  
                  // 更新最后报警时间和索引
                  last_dragon_down_time = signal_time;
                  last_dragon_down_bar = i;
               }
            }
            
            // ========== 第五步：上涨信号判断与触发 ==========
            // 上涨信号触发条件（五个条件必须同时满足）：
            // 1. dragon_sindex > DragonQual：连续下跌次数超过质量阈值（表明已有足够的下跌动能，准备反弹）
            // 2. close[i] > open[i]：当前K线为阳线（价格开始反弹的确认信号）
            // 3. low[i] <= iLow(...)：当前最低价达到或低于DragonLen周期内的最低点（触及支撑位）
            // 4. i < rates_total - 1：确保K线已收盘（不是当前正在形成的K线）
            // 5. 防止重复信号：确保不在同一K线上重复触发信号
            // 注意：原始指标使用 rates_total-1-(i-1) = rates_total-i 来计算iLowest的shift参数
            // 这个计算方式是为了从当前位置向前回看DragonLen个周期
            if((dragon_sindex > DragonQual) && (close[i] > open[i]) && 
               (low[i] <= iLow(NULL, 0, iLowest(NULL, 0, MODE_LOW, DragonLen, rates_total-1-(i-1)))) &&
               // 已移除趋势线过滤条件
               (i < rates_total - 1))  // 确保K线已收盘
            {
               // 详细信号触发日志
               Print("[神龙通道] *** 上涨信号触发 *** K线[", i, "] dragon_sindex=", dragon_sindex, ", DragonQual=", DragonQual);
               Print("[神龙通道] 触发条件: close[", i, "]=", close[i], " > open[", i, "]=", open[i], ", low[", i, "]=", low[i]);
               Print("[神龙通道] K线收盘确认: i=", i, " < rates_total-1=", rates_total-1, " (K线已收盘)");
               Print("[神龙通道] 信号位置: low[", i, "]=", low[i], ", 偏移=", smart_offset, ", 箭头位置=", low[i] - smart_offset);
               Print("[神龙通道] 设置上涨箭头: DragonUpBuffer[", i, "] = ", low[i] - smart_offset);
               
               // 记录信号触发状态，防止重复信号
               signal_triggered = true;
               last_signal_bar = i;
               
               // 在最低价下方显示上涨箭头（减去偏移量避免与价格重叠）
               DragonUpBuffer[i] = low[i] - smart_offset;
               
               // ========== 警报和通知逻辑 ==========
               // 确定警报基于的K线位置
               int whichBar = i;  // 默认基于前一根K线
               // if (DragonCurrentBar == INPUT_YES) whichBar = i;  // 可选择基于当前K线
       
               // 只对最新的几根K线触发警报，避免历史数据弹窗
               // 只有当信号出现在最近3根K线内时才触发警报
               // 第一次加载时（prev_calculated == 0）也允许最近的信号报警
               bool isRecentSignal = (i >= rates_total - 3);
               
               // 使用K线时间和索引双重防止重复报警
               datetime signal_time = time[i];
               // 检查冷却期：信号触发后至少3根K线内不再触发
               bool inCooldown = false;
               if(last_dragon_up_bar >= 0 && i - last_dragon_up_bar < 3)
               {
                  inCooldown = true;
               }
               
               // 调试信息
               Print("[神龙通道-上] 检查报警条件: i=", i, ", rates_total=", rates_total, ", isRecentSignal=", isRecentSignal, 
                     ", signal_time=", TimeToString(signal_time), ", last_dragon_up_time=", TimeToString(last_dragon_up_time),
                     ", last_dragon_up_bar=", last_dragon_up_bar, ", inCooldown=", inCooldown, 
                     ", prev_calculated=", prev_calculated, ", dragon_init_call_count=", dragon_init_call_count);
               
               // 首次运行时需要特殊处理，避免重复报警
               bool shouldAlert = false;
               if(prev_calculated == 0 && dragon_init_call_count <= 2)
               {
                  // 初始化阶段，只在第一次调用且是最新信号时报警
                  shouldAlert = isRecentSignal && !inCooldown && (i == rates_total - 2) && (dragon_init_call_count == 1);
               }
               else
               {
                  // 非首次运行，正常检查
                  shouldAlert = isRecentSignal && !inCooldown && last_dragon_up_time != signal_time;
               }
               
               if (shouldAlert)
               {
                  Print("[神龙通道-上] 满足报警条件，准备发送报警");
                  
                  // 弹窗警报
                  if (DragonAlert == INPUT_YES)
                  {
                     string alert_message = Symbol() + ", " + TimeframeToString(Period()) + ": Reverse:Arrow up " + TimeToString(signal_time);
                     Print("[神龙通道] 发送警报: ", alert_message); 
                     Alert(alert_message);
                  }
                  
                  // 邮件通知
                  if (DragonMail == INPUT_YES && TerminalInfoInteger(TERMINAL_EMAIL_ENABLED))
                  {
                     SendFormattedEmail("Reverse:Arrow up", "信号类型: Reverse:Arrow up\n", time[i], close[i]);
                     Print("[神龙通道] 发送邮件: Reverse:Arrow up");
                  }
                  
                  // 更新最后报警时间和索引
                  last_dragon_up_time = signal_time;
                  last_dragon_up_bar = i;
               }
            }
         }

         // ========== 神龙通道计算逻辑结束 ==========


         // 已移除复杂计算逻辑，只保留神龙信号需要的部分
         
         // 已移除所有红线绿线和趋势线计算
         
         
         // 已移除不必要的计算逻辑
         
         // 已删除所有MA均线计算和填充区域绘制
         
         // 已移除交叉检测相关代码
      
         // 已移除调试输出代码
         
      }
      
      
      // 已禁用额外的邮件通知逻辑，只保留神龙信号的内建通知
      
      // 验证神龙通道箭头缓冲区状态（调试用）
      int arrow_count = 0;
      for(int i = 0; i < rates_total; i++)
      {
         if(DragonUpBuffer[i] != EMPTY_VALUE) arrow_count++;
         if(DragonDownBuffer[i] != EMPTY_VALUE) arrow_count++;
      }
      if(arrow_count > 0)
      {
         // Print("[神龙通道] 缓冲区验证: 共发现 ", arrow_count, " 个箭头信号在缓冲区中");
      }
      
      // 已删除K线颜色设置功能调用
      
      
      
      return(rates_total);
   }




   //+------------------------------------------------------------------+
   //| Timeframe to string                                              |
   //+------------------------------------------------------------------+
   string TimeframeToString(const ENUM_TIMEFRAMES timeframe)
   {
      return StringSubstr(EnumToString(timeframe), 7);
   }

   //+------------------------------------------------------------------+
   //| 指标去初始化函数                                                    |
   // 已删除SetCandleColors函数

   //+------------------------------------------------------------------+
   void OnDeinit(const int reason)
   {
      // 清理所有创建的对象
      ObjectsDeleteAll(0, 0, OBJ_TEXT);
      
      
      // 释放ATR句柄
      if(atr_handle != INVALID_HANDLE)
         IndicatorRelease(atr_handle);
   }